<?php

class WebActionResponder extends WebResponder {
	private $signatures = null;
	public function signatures() {
		if (!is_null($this->signatures)) return $this->signatures;
		
		$a = array();
		$x = new ReflectionClass($this);
		foreach ($x->getConstants() as $name => $value) {
			if (substr($name, 0, 5) != '_web_') continue;
			$sign = WebSignatureFromValue($value);
			if ($value) $a[substr($name, 5)] = $sign;
		}
		
		foreach (get_class_vars(get_class($this)) as $name => $value) {
			if (substr($name, 0, 5) != '_web_') continue;
			$sign = WebSignatureFromValue($value);
			if ($value) $a[substr($name, 5)] = $sign;
		}
		
		$this->signatures = $a;
		return $a;
	}
	
	public function performAction(WebAction $a) {
		CLog($a, __METHOD__);
		
		try {
			$m = new ReflectionMethod($this, $a->name());

			$args = array();
			foreach ($m->getParameters() as $param)
				$args[] = $a->captureForKey($param->getName());
			
			return $this->resultForActionResponse(
				$m->invokeArgs($this, $args));
		} catch (ReflectionException $e) {
			return $this->performUnknownAction($a);
		}
	}
	
	public function resultFromString($s) {
		return WebResponse::makeNew()
			->setBody($s);
	}
	
	public function resultForActionResponse($result) {
		if (is_string($result))
			return $this->resultFromString($result);
		else if (is_object($result)) {
			if ($result instanceof WebResponse) {
				return $result;
			} else {
				
				$m = CNameOfMethodWithClassOfObject($this, 'resultFrom', $result);
				if ($m)
					return $this->$m($result);
				else {
					$x = CUnimplementedException("resultForActionResponse not overridden or no resultFrom<ClassName> method found for result object of class " . get_class($result) . ".");
					$x->reasonObject = $result; // TODO
					throw $x;
				}
				
			}
		}
	}
	
	public function performWithoutMatchingAction() {
		throw new CNotFoundException($this);
	}
	
	public function performUnknownAction(WebAction $a) {
		throw new CNotFoundException($this);
	}
	
	function newSignatureMatcher() {
		return new WebSignatureMatcher();
	}
	
	function actionForRequest(IWebRequest $r) {
		$signs = $this->signatures();
		$captures = null;
		$matcher = $this->newSignatureMatcher();
		
		foreach ($signs as $name => $sign) {
			$matches =
				$matcher->signatureMatches($r, $sign, $captures);
			
			if ($matches) {
				return WebAction::makeNew()
					->setName($name)
					->setCaptures($captures);
			}
		}
		
		return null;
	}
	
	function dispatchActionForRequest(IWebRequest $r) {
		$action = $this->actionForRequest($r);
		if ($action)
			return $this->performAction($action);
		else
			return $this->performWithoutMatchingAction();
	}
	
	function responseForRequest(IWebRequest $r) {
		return
		$this->callAndPassExceptionToResponder(
			array($this, 'dispatchActionForRequest'),
			array($r)
		);
	}
	
	public static function runFirstToRespond(array $resp, IWebRequest $req) {
		foreach ($resp as $r) {
			$x = null;
			try {
				$x = $r->dispatchActionForRequest($req);
			} catch (CNotFoundException $e) {
				$x = null;
			} catch (Exception $e) {
				$x = $r->exceptionHandler($e);
			}
			
			if ($x) { $x->render(); return; }
		}
	}
}

?>